/**
 * 基本类型
 */
// 1. number 数字类型
let num: number = 10;
// 2. string 字符串类型
let str: string = "Hello World";
// 3. boolean 布尔类型
let bool: boolean = true; 

/**
 * 对象与函数
 */
// 4. object 对象类型 很少使用 因为对象目的是限制其中的属性值 let obj: object = {name: "John", age: 30}; 
// 4.1. 代表对象中必须要有一个name属性属性值必须是string类型 定义多少写多少 不写报错 多写报错 但是可以通过 ? 表示该属性是可选属性
let obj1 : {name: string, age?: number} = {name: "John", age: 30}
// 4.2. 可以通过特定方式为该对象添加任意多个属性 实测propName叫什么都行
let obj2 : {name: string, [propName: string]: any} = {name: "John", age: 30, gender: "male"}

// 5. 函数的定义方式 定义时形参可以不一致
let fn3 : (a:number, b:number) => number 
fn3 = function(x:number, y:number): number {
  return x + y;
}
// 6. void 空类型 设置函数返回值
function fn1(): void {
  // 代表没有返回值 不应该有return返回值
}
// 7. never 类型 
function fn2(): never {
  // 代表永远不会返回的函数 例如抛出异常
  throw new Error("Error");
}

/**
 * 其他类型
 */

// 8. array 数组类型 可以指定元素类型 保证其纯粹性 同样是两种写法
// 写法1
let arr1: number[] = [1, 2, 3];
let arr2: Array<string> = ['1', '2', '3'];
// 写法2
let arr4: (number | string)[] = [1, '2', 3];
let arr3: Array<number | string> = [1, '2', 3];

// 9. tuple 元组类型 固定长度的数组 定义多少写多少并且类型必须一致
let tuple: [string, number] = ["Hello", 10]; 

// 10. enum 枚举类型 通过枚举来定义一组固定的值 就是可选值
let color: "red" | "green" | "blue" = "red"; 
// 写法1 
let obj3: {name: string, age: number, gender: "male" | "female"} = {name: "John", age: 30, gender: "male"};
// 写法2 
enum Gender{
  Male,
  Female
}
let obj4: {name: string, age: number, gender: Gender} = {name: "John", age: 30, gender: Gender.Male};


// 11. 字面量
let a: 'male' | 'female' = 'female';


// 12. null 和 undefined 类型
let nullVal: null = null; 
let undefinedVal: undefined = undefined;  


/**
 * 特殊类型
 */

// 13. any 任意类型 具有传染性 在被赋值给其他类型时会将其类型转换为any
let anything: any = "Hello World"; 
// unknown 未知类型 解决any的问题 进行类型检查
let unknownVal: unknown = "Hello World"; 


/**
 * 特殊使用
 */
// 1. 类型断言 有两种方式 直接告诉编译器变量是什么类型
let e;
// num = e as number; 
num = <number>e

// 2. 联合类型 针对对象 基础值不可能既是string又是number
let j: {name: string} & {age: number} = {name: "John", age: 30}; 

// 3. 类型别名 给一个类型起一个别名 方便使用
type typeAlias = [number, string]
let arrEnum: typeAlias;

// 函数有参数类型与返回值类型
function greet(name: string): string {
    return "Hello " + name;
}

export {}